package com.roadmap.client.sns;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import org.hibernate.Hibernate;

import com.roadmap.client.module.BaseManager;
import com.roadmap.common.BaseConst;
import com.roadmap.common.BaseEntity;
import com.roadmap.common.BaseEnum.ActionType;
import com.roadmap.entities.Friendship;
import com.roadmap.entities.Request;
import com.roadmap.entities.ext.RequestExt;
import com.roadmap.exception.ActionNotSupportedException;
import com.roadmap.exception.EntityNotFoundException;
import com.roadmap.exception.InvalidActionException;
import com.roadmap.exception.InvalidQueryException;
import com.roadmap.exception.InvalidStatusException;
import com.roadmap.exception.InvalidValueException;
import com.roadmap.exception.NullObjectException;
import com.roadmap.exception.ServerException;
import com.roadmap.repo.db.RdcQuery;

/* manage quests for applying for a friendship.
 * */
public class RequestManager extends BaseManager {

	public RequestManager(String parentId) {
		super(parentId, Request.class);
	}

	/** reject a request */
	@Override
	public void cancel(BaseEntity entity) throws NullObjectException,
			InvalidActionException, InvalidValueException, ServerException,
			EntityNotFoundException, ActionNotSupportedException {
		if (!checkEntityIsValid(entity)) {
			return;
		}
		Request request = (Request) entity;
		request.setStatus(BaseConst.REQUEST_STATUS_REJECTED);
		getDbUtil().update(request);
	}

	/**
	 * approve a request.
	 * 
	 * @throws InvalidStatusException
	 */
	@Override
	public void complete(BaseEntity entity) throws NullObjectException,
			InvalidActionException, InvalidValueException, ServerException,
			EntityNotFoundException, ActionNotSupportedException,
			InvalidStatusException {
		if (!checkEntityIsValid(entity)) {
			return;
		}

		Request request = (Request) entity;
		// check if there's already a relationship stored in the database. if
		// not, create a new record, or else just update the request.
		Friendship frd = getFriend(request.getId(), request.getRecipientId());
		if (frd == null) {
			// change the request to APPROVED status.
			request.setStatus(BaseConst.REQUEST_STATUS_APPROVED);
			Vector<BaseEntity> entities = new Vector<BaseEntity>();
			entities.add(request);
			// create a friendship. the request recipient becomes a friend of
			// the dispatcher.
			frd = new Friendship();
			frd.setId(request.getId());
			frd.setFriendId(request.getRecipientId());
			entities.add(frd);
			getDbUtil().saveOrUpdateEntities(entities);

			getNoticeManager().notifyForEntry(frd, ActionType.ACCEPT, null);
		}
	}

	/**
	 * send a request.
	 */
	@Override
	public void create(BaseEntity entity) throws NullObjectException,
			InvalidActionException, InvalidValueException, ServerException,
			EntityNotFoundException, ActionNotSupportedException,
			InvalidStatusException {
		if (!checkEntityIsValid(entity)) {
			return;
		}
		Request request = (Request) entity;
		// check if the two user are friends already.
		Friendship frd = getFriend(request.getId(), request.getRecipientId());
		if (frd != null) {
			// if they're friends,
			throw new InvalidActionException("they're already friends.");
		}

		// query in the database, check if there's a record of the request. if
		// the request exists and its status is REJECTED or COMPLETED, update
		// the record, or else throw an exception.
		Request req = get(request.getId(), request.getRecipientId());
		if (req == null) {
			getDbUtil().save(request);
		}
		else {
			// update the request
			req.setStatus(BaseConst.REQUEST_STATUS_NEW);
			req.setNote(request.getNote());
			req.setCreatedTime(request.getCreatedTime());
			getDbUtil().update(req);
		}
	}

	/** return a list of unread requests */
	@Override
	public List<RequestExt> getEntitiesOfAspirant() throws NullObjectException,
			InvalidQueryException, ServerException, InvalidValueException {
		String sql = "select {r.*}, a.realName from request as r, aspirant as a where r.recipientId=:uid and r.status=:state and r.dispatcherId=a.aspirantId order by createdTime DESC";
		RdcQuery query = getDbUtil().createNativeSQLQuery(sql);
		query.addEntity("r", Request.class);
		query.setParameter("uid", getOwnerId());
		query.setParameter("state", BaseConst.REQUEST_STATUS_NEW);
		query.addScalar("realName", Hibernate.STRING);
		List results = query.getResults();
		if (results != null && !results.isEmpty()) {
			List<RequestExt> requests = new ArrayList<RequestExt>();
			Iterator iter = results.iterator();
			while (iter.hasNext()) {
				Object[] result = (Object[]) iter.next();
				RequestExt ext = new RequestExt((Request) result[0]);
				ext.setRequester((String) result[1]);
				requests.add(ext);
			}

			return requests;
		}
		return null;
	}

	/** a request identified by the combination of two users ignoring the order */
	private Request get(String userAId, String userBId)
			throws NullObjectException, InvalidQueryException, ServerException,
			InvalidValueException {
		if (userAId == null || userBId == null) {
			return null;
		}
		String hql = "from Request where (id=? and recipientId=?) or (id=? and recipientId=?)";
		Object[] params = { userAId, userBId, userBId, userBId };
		List list = getDbUtil().executeHQLQuery(hql, params);
		if (list != null && list.size() == 1) {
			return (Request) (list.get(0));
		}
		return null;
	}

	private Friendship getFriend(String disId, String repId)
			throws ServerException {
		if (disId == null || repId == null) {
			return null;
		}
		String hql = "from Friendship where (id=? and friendId=?) or (id=? and friendId=?)";
		Object[] params = { disId, repId, repId, disId };
		return (Friendship) getDbUtil().getUniqueEntity(hql, params);
	}
}
